using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing.Drawing2D;
using MyExtensions;

namespace LibNDSFormats.NSBMD
{
    public partial class NSBMDInfo : Form
    {
        Nsbmd inf;
        public NSBMDInfo(Nsbmd m)
        {
            InitializeComponent();
            this.SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint | ControlStyles.DoubleBuffer, true);
            inf = m;
            imageList1.Images.Add(MKDS_Course_Editor.Properties.Resources.model_wireframe);
            imageList1.Images.Add(MKDS_Course_Editor.Properties.Resources.model_joint);
            imageList1.Images.Add(MKDS_Course_Editor.Properties.Resources.model_solid);
            imageList1.Images.Add(MKDS_Course_Editor.Properties.Resources.model_texture);
            imageList1.Images.Add(MKDS_Course_Editor.Properties.Resources.picture);
            imageList1.Images.Add(MKDS_Course_Editor.Properties.Resources.color_swatch);
        }

        private void NSBMDInfo_Load(object sender, EventArgs e)
        {
            TreeNode t;
            for (int i = 0; i < inf.models.Length; i++)
            {
                t = new TreeNode(inf.models[i].Name);
                t.ImageIndex = 0;
                t.SelectedImageIndex = 0;
                t.StateImageIndex = 0;
                t.Tag = inf.models[i];
                treeView1.Nodes.Add(t);
                List<TreeNode> n = new List<TreeNode>();
                for (int j = 0; j < inf.models[i].Objects.Count; j++)
                {
                    t = new TreeNode(inf.models[i].Objects[j].Name);
                    t.ImageIndex = 1;
                    t.SelectedImageIndex = 1;
                    t.StateImageIndex = 1;
                    t.Tag = inf.models[i].Objects[j];
                    if (inf.models[i].Objects[j].ParentID == j)
                    {
                        n.Add(treeView1.Nodes[i].Nodes[treeView1.Nodes[i].Nodes.Add(t)]);
                    }
                    else
                    {
                        n.Add(n[inf.models[i].Objects[j].ParentID].Nodes[n[inf.models[i].Objects[j].ParentID].Nodes.Add(t)]);
                    }
                    for (int k = 0; k < inf.models[i].Objects[j].childs.Count; k++)
                    {
                        t = new TreeNode(inf.models[i].Polygons[inf.models[i].Objects[j].childs[k]].Name);
                        t.ImageIndex = 2;
                        t.SelectedImageIndex = 2;
                        t.StateImageIndex = 2;
                        t.Tag = inf.models[i].Polygons[inf.models[i].Objects[j].childs[k]];
                        n[j].Nodes.Add(t);
                        if (inf.models[i].Polygons[inf.models[i].Objects[j].childs[k]].MatId != -1)
                        {
                            t = new TreeNode(inf.models[i].Materials[inf.models[i].Polygons[inf.models[i].Objects[j].childs[k]].MatId].MaterialName);
                            t.ImageIndex = 3;
                            t.SelectedImageIndex = 3;
                            t.StateImageIndex = 3;
                            t.Tag = inf.models[i].Materials[inf.models[i].Polygons[inf.models[i].Objects[j].childs[k]].MatId];
                            n[j].Nodes[k].Nodes.Add(t);
                            if (inf.models[i].Materials[inf.models[i].Polygons[inf.models[i].Objects[j].childs[k]].MatId].format != 0)
                            {
                                t = new TreeNode(inf.models[i].Materials[inf.models[i].Polygons[inf.models[i].Objects[j].childs[k]].MatId].texname);
                                t.ImageIndex = 4;
                                t.SelectedImageIndex = 4;
                                t.StateImageIndex = 4;
                                t.Tag = inf.models[i].Materials[inf.models[i].Polygons[inf.models[i].Objects[j].childs[k]].MatId];
                                n[j].Nodes[k].Nodes[0].Nodes.Add(t);
                                if (inf.models[i].Materials[inf.models[i].Polygons[inf.models[i].Objects[j].childs[k]].MatId].format != 7)
                                {
                                    t = new TreeNode(inf.models[i].Materials[inf.models[i].Polygons[inf.models[i].Objects[j].childs[k]].MatId].palname);
                                    t.ImageIndex = 5;
                                    t.SelectedImageIndex = 5;
                                    t.StateImageIndex = 5;
                                    t.Tag = inf.models[i].Materials[inf.models[i].Polygons[inf.models[i].Objects[j].childs[k]].MatId];
                                    n[j].Nodes[k].Nodes[0].Nodes[0].Nodes.Add(t);
                                }
                            }
                        }
                    }
                }
            }
            treeView1.SelectedNode = treeView1.Nodes[0];
        }

        private void panel1_Paint(object sender, PaintEventArgs e)
        {
            if (treeView1.SelectedNode != null)
            {
                e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
                e.Graphics.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
                e.Graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor;
                switch (treeView1.SelectedNode.ImageIndex)
                {
                    case 0: //Model
                        {
                            NsbmdModel m = treeView1.SelectedNode.Tag as NsbmdModel;
                            e.Graphics.DrawImage(imageList1.Images[0], 5, 5);
                            e.Graphics.DrawString(m.Name + ": Model", SystemFonts.DefaultFont, Brushes.Black, 25, 5);
                            break;
                        }
                    case 1: //Joint
                        {
                            NsbmdObject m = treeView1.SelectedNode.Tag as NsbmdObject;
                            e.Graphics.DrawImage(imageList1.Images[1], 5, 5);
                            e.Graphics.DrawString(m.Name + ": Joint", SystemFonts.DefaultFont, Brushes.Black, 25, 5);
                            break;
                        }
                    case 2: //Polygon
                        {
                            NsbmdPolygon m = treeView1.SelectedNode.Tag as NsbmdPolygon;
                            e.Graphics.DrawImage(imageList1.Images[2], 5, 5);
                            e.Graphics.DrawString(m.Name + ": Polygon", SystemFonts.DefaultFont, Brushes.Black, 25, 5);
                            break;
                        }
                    case 3: //Material
                        {
                            NsbmdMaterial m = treeView1.SelectedNode.Tag as NsbmdMaterial;
                            e.Graphics.DrawImage(imageList1.Images[3], 5, 5);
                            e.Graphics.DrawString(m.MaterialName + ": Material", SystemFonts.DefaultFont, Brushes.Black, 25, 5);
                            if (((m.PolyAttrib >> 0xf) & 0x1) == 1)
                            {
                                e.Graphics.DrawString("Use Lighting: Yes", SystemFonts.DefaultFont, Brushes.Black, 25, 30);
                                if (((m.PolyAttrib >> 0) & 0x1) == 1) e.Graphics.DrawImage(MKDS_Course_Editor.Properties.Resources.light_bulb, 25, 50);
                                else e.Graphics.DrawImage(MKDS_Course_Editor.Properties.Resources.light_bulb_off, 25, 50);
                                if (((m.PolyAttrib >> 1) & 0x1) == 1) e.Graphics.DrawImage(MKDS_Course_Editor.Properties.Resources.light_bulb, 75, 50);
                                else e.Graphics.DrawImage(MKDS_Course_Editor.Properties.Resources.light_bulb_off, 75, 50);
                                if (((m.PolyAttrib >> 2) & 0x1) == 1) e.Graphics.DrawImage(MKDS_Course_Editor.Properties.Resources.light_bulb, 125, 50);
                                else e.Graphics.DrawImage(MKDS_Course_Editor.Properties.Resources.light_bulb_off, 125, 50);
                                if (((m.PolyAttrib >> 3) & 0x1) == 1) e.Graphics.DrawImage(MKDS_Course_Editor.Properties.Resources.light_bulb, 175, 50);
                                else e.Graphics.DrawImage(MKDS_Course_Editor.Properties.Resources.light_bulb_off, 175, 50);
                            }
                            else
                            {
                                e.Graphics.DrawString("Use Lighting: No", SystemFonts.DefaultFont, Brushes.Black, 25, 30);
                                Image off = ColorImageToGrayScaleImage(MKDS_Course_Editor.Properties.Resources.light_bulb_off);
                                e.Graphics.DrawImage(off, 25, 50);
                                e.Graphics.DrawImage(off, 75, 50);
                                e.Graphics.DrawImage(off, 125, 50);
                                e.Graphics.DrawImage(off, 175, 50);
                            }
                            e.Graphics.DrawRectangle(Pens.DarkGray, new Rectangle(24, 75 + 0 * 40 - 1, 33, 33));
                            e.Graphics.DrawRectangle(Pens.DarkGray, new Rectangle(199, 75 + 0 * 40 - 1, 33, 33));
                            e.Graphics.DrawRectangle(Pens.DarkGray, new Rectangle(24, 75 + 1 * 40 - 1, 33, 33));
                            e.Graphics.DrawRectangle(Pens.DarkGray, new Rectangle(199, 75 + 1 * 40 - 1, 33, 33));
                            e.Graphics.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality;
                            e.Graphics.FillRectangle(new SolidBrush(m.DiffuseColor), new Rectangle(25, 75 + 0 * 40, 32, 32));
                            e.Graphics.FillRectangle(new SolidBrush(m.AmbientColor), new Rectangle(200, 75 + 0 * 40, 32, 32));
                            e.Graphics.FillRectangle(new SolidBrush(m.SpecularColor), new Rectangle(25, 75 + 1 * 40, 32, 32));
                            e.Graphics.FillRectangle(new SolidBrush(m.EmissionColor), new Rectangle(200, 75 + 1 * 40, 32, 32));
                            e.Graphics.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.Default;
                            e.Graphics.DrawString("Diffuse", SystemFonts.DefaultFont, Brushes.Black, 60, 84 + 0 * 40);
                            e.Graphics.DrawString("Ambient", SystemFonts.DefaultFont, Brushes.Black, 235, 84 + 0 * 40);
                            e.Graphics.DrawString("Specular", SystemFonts.DefaultFont, Brushes.Black, 60, 84 + 1 * 40);
                            e.Graphics.DrawString("Emission", SystemFonts.DefaultFont, Brushes.Black, 235, 84 + 1 * 40);

                            e.Graphics.DrawString("Texture Repeat S:", SystemFonts.DefaultFont, Brushes.Black, 25, 160);
                            if (m.flipS == 1 && m.repeatS == 1)
                            {
                                e.Graphics.DrawString("Flip & Repeat", SystemFonts.DefaultFont, Brushes.Black, 150, 160);
                            }
                            else if (m.repeatS == 1)
                            {
                                e.Graphics.DrawString("Repeat", SystemFonts.DefaultFont, Brushes.Black, 150, 160);
                            }
                            else
                            {
                                e.Graphics.DrawString("Clamp", SystemFonts.DefaultFont, Brushes.Black, 150, 160);
                            }
                            e.Graphics.DrawString("Texture Repeat T:", SystemFonts.DefaultFont, Brushes.Black, 25, 180);
                            if (m.flipT == 1 && m.repeatT == 1)
                            {
                                e.Graphics.DrawString("Flip & Repeat", SystemFonts.DefaultFont, Brushes.Black, 150, 180);
                            }
                            else if (m.repeatT == 1)
                            {
                                e.Graphics.DrawString("Repeat", SystemFonts.DefaultFont, Brushes.Black, 150, 180);
                            }
                            else
                            {
                                e.Graphics.DrawString("Clamp", SystemFonts.DefaultFont, Brushes.Black, 150, 180);
                            }
                            e.Graphics.DrawString("Alpha:", SystemFonts.DefaultFont, Brushes.Black, 25, 200);
                            e.Graphics.DrawString(m.Alpha.ToString() + " / 31", SystemFonts.DefaultFont, Brushes.Black, 150, 200);
                            e.Graphics.DrawString("Polygon Mode:", SystemFonts.DefaultFont, Brushes.Black, 25, 220);
                            e.Graphics.DrawString(PolygonMode[(m.PolyAttrib >> 4) & 0x3], SystemFonts.DefaultFont, Brushes.Black, 150, 220);
                            e.Graphics.DrawString("Surface to Display:", SystemFonts.DefaultFont, Brushes.Black, 25, 240);
                            switch (m.PolyAttrib >> 6 & 0x03)
                            {
                                case 0x03: e.Graphics.DrawString("Both Faces", SystemFonts.DefaultFont, Brushes.Black, 150, 240); break;
                                case 0x02: e.Graphics.DrawString("Front Face", SystemFonts.DefaultFont, Brushes.Black, 150, 240); break;
                                case 0x01: e.Graphics.DrawString("Back Face", SystemFonts.DefaultFont, Brushes.Black, 150, 240); break;
                            }
                            e.Graphics.DrawString("Is EnvironmentMap:", SystemFonts.DefaultFont, Brushes.Black, 25, 260);
                            e.Graphics.DrawString(m.isEnvironmentMap ? "Yes" : "No", SystemFonts.DefaultFont, Brushes.Black, 150, 260);
                            Color[] c;
                            if (m.format != 7 && m.format != 0)
                            {
                                c = new Color[m.paldata.Length];
                                for (int i = 0; i < m.paldata.Length; i++)
                                {
                                    c[i] = m.paldata[i].ToColor();
                                }
                            }
                            else c = new Color[0];
                            DrawMaterialBall(270, 5, e.Graphics, m.DiffuseColor, m.AmbientColor, m.SpecularColor, m.EmissionColor,(m.format != 0?ConvertImage(m.texdata, c, m.format, m.width, m.height, m.spdata, m.color0 == 1):null), m);
                            break;
                        }
                    case 4: //Texture
                        {
                            NsbmdMaterial m = treeView1.SelectedNode.Tag as NsbmdMaterial;
                            e.Graphics.DrawImage(imageList1.Images[4], 5, 5);
                            e.Graphics.DrawString(m.texname + ": Texture", SystemFonts.DefaultFont, Brushes.Black, 25, 5);
                            Color[] c;
                            if (m.format != 7)
                            {
                                c = new Color[m.paldata.Length];
                                for (int i = 0; i < m.paldata.Length; i++)
                                {
                                    c[i] = m.paldata[i].ToColor();
                                }
                            }
                            else c = new Color[0];
                            int NewWidth = 128;
                            int NewHeight = m.height * NewWidth / m.width;
                            if (NewHeight > 128) // Height resize if necessary
                            {
                                NewWidth = m.width * 128 / m.height;
                                NewHeight = 128;
                            }
                            e.Graphics.DrawRectangle(Pens.DarkGray, new Rectangle(24, 29, 129, 129));
                            e.Graphics.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality;
                            e.Graphics.DrawImage(ConvertImage(m.texdata, c, m.format, m.width, m.height, m.spdata, m.color0 == 1), 25, 30, NewWidth, NewHeight);
                            e.Graphics.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.Default;
                            e.Graphics.DrawString("Width:", SystemFonts.DefaultFont, Brushes.Black, 25, 180);
                            e.Graphics.DrawString(m.width.ToString(), SystemFonts.DefaultFont, Brushes.Black, 150, 180);
                            e.Graphics.DrawString("Height:", SystemFonts.DefaultFont, Brushes.Black, 25, 200);
                            e.Graphics.DrawString(m.height.ToString(), SystemFonts.DefaultFont, Brushes.Black, 150, 200);
                            e.Graphics.DrawString("Format:", SystemFonts.DefaultFont, Brushes.Black, 25, 220);
                            e.Graphics.DrawString(formatNames[m.format], SystemFonts.DefaultFont, Brushes.Black, 150, 220);
                            if (m.format == 2 || m.format == 3 || m.format == 4)
                            {
                                e.Graphics.DrawString("Palette Color 0 Mode: ", SystemFonts.DefaultFont, Brushes.Black, 25, 240);
                                e.Graphics.DrawString((m.color0 == 0 ? "Use As a Color" : "Use As a Transparent Color"), SystemFonts.DefaultFont, Brushes.Black, 150, 240);
                            }
                            else
                            {
                                e.Graphics.DrawString("Palette Color 0 Mode:", SystemFonts.DefaultFont, Brushes.White, 26, 241);
                                e.Graphics.DrawString("Palette Color 0 Mode:", SystemFonts.DefaultFont, Brushes.Gray, 25, 240);
                                e.Graphics.DrawString("---", SystemFonts.DefaultFont, Brushes.White, 151, 241);
                                e.Graphics.DrawString("---", SystemFonts.DefaultFont, Brushes.Gray, 150, 240);
                            }
                            break;
                        }
                    case 5: //Palette
                        {
                            NsbmdMaterial m = treeView1.SelectedNode.Tag as NsbmdMaterial;
                            e.Graphics.DrawImage(imageList1.Images[5], 5, 5);
                            e.Graphics.DrawString(m.palname + ": Palette", SystemFonts.DefaultFont, Brushes.Black, 25, 5);
                            e.Graphics.DrawRectangle(Pens.DarkGray, new Rectangle(24, 29, 129, 129));
                            e.Graphics.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality;
                            if (m.format != 5)
                            {
                                for (int i = 0; i < m.paldata.Length; i += 16)
                                {
                                    for (int j = 0; j < 16; j++)
                                    {
                                        if (m.paldata.Length != i + j)
                                        {
                                            e.Graphics.FillRectangle(new SolidBrush(m.paldata[i + j].ToColor()), j * 8 + 25, i / 16 * 8 + 30, 8, 8);
                                        }
                                        else goto end;
                                    }
                                }
                            }
                            else
                            {
                                for (int i = 0; i < m.paldata.Length; i += 64)
                                {
                                    for (int j = 0; j < 64; j++)
                                    {
                                        if (m.paldata.Length != i + j)
                                        {
                                            e.Graphics.FillRectangle(new SolidBrush(m.paldata[i + j].ToColor()), j * 2 + 25, i / 64 * 2 + 30, 2, 2);
                                        }
                                        else goto end;
                                    }
                                }
                            }
                        end:
                            e.Graphics.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.Default;
                            e.Graphics.DrawString("Colors:", SystemFonts.DefaultFont, Brushes.Black, 25, 180);
                            e.Graphics.DrawString(m.paldata.Length.ToString(), SystemFonts.DefaultFont, Brushes.Black, 150, 180);
                            break;
                        }
                }
            }
        }
        void DrawMaterialBall(int x, int y, Graphics g, Color diff, Color amb, Color spe, Color emi, Bitmap img, NsbmdMaterial m)
        {
            g.SmoothingMode = SmoothingMode.HighQuality;
            if (img != null)
            {
                for (int i = 0; i < img.Width; i++)
                {
                    for (int j = 0; j < img.Height; j++)
                    {
                        img.SetPixel(i, j, getMeanColor(diff, img.GetPixel(i, j)));
                    }
                }
                TextureBrush t = new TextureBrush(img);
                if (m.flipS == 1 && m.flipT == 1)
                {
                    t.WrapMode = WrapMode.TileFlipXY;
                }
                else if (m.flipS == 1)
                {
                    t.WrapMode = WrapMode.TileFlipX;
                }
                else if (m.flipT == 1)
                {
                    t.WrapMode = WrapMode.TileFlipY;
                }
                else if (m.repeatS == 1 && m.repeatT == 1)
                {
                    t.WrapMode = WrapMode.Tile;
                }
                else if (m.repeatS == 0 && m.repeatT == 0)
                {
                    t.WrapMode = WrapMode.Clamp;
                }
                //g.FillEllipse(t, x, y, 64, 64);
            }
            else
            {
                //g.FillEllipse(new SolidBrush(diff), x, y, 64, 64);
            }
            g.FillEllipse(new SolidBrush(diff), x, y, 64, 64);
            g.FillRadialGradient(x, y, 64, 64, new PointF(x + 25, y + 25), Color.FromArgb(0, 0, 0, 0), new Color[] { Color.FromArgb(127, 0, 0, 0) });
            g.FillRadialGradient(x, y, 64, 64, new PointF(x+25, y+25), Color.FromArgb(0, amb), new Color[] { Color.FromArgb(127, amb) });
            g.FillRadialGradient(x +12, y + 12, 16, 16, new PointF(x+12+4, y+12+4), spe, new Color[] { Color.FromArgb(0, spe) });

            //gr = new LinearGradientBrush(new Point(64, 0), new Point(64, 128), Color.FromArgb(0, 0, 0, 0), Color.FromArgb(255, 0, 0, 0));
            //g.FillEllipse(gr, x + 16, y + 16, 16, 16);
        }
        private Color[] BlendColors(Color start, Color end, int steps)
        {
            Color[] colorPalette = new Color[steps];
            double colorFactor = 100 / Convert.ToDouble(steps) / 100;
            for (int colorLevel = 0; colorLevel < steps; colorLevel++)
            {
                double endColorQuantity = (colorLevel + 1) * colorFactor;
                double startColorQuantity = 1 - endColorQuantity;
                colorPalette[colorLevel] = Color.FromArgb(255,
                Math.Abs(Convert.ToInt32(end.R * endColorQuantity + start.R * startColorQuantity)),
                Math.Abs(Convert.ToInt32(end.G * endColorQuantity + start.G * startColorQuantity)),
                Math.Abs(Convert.ToInt32(end.B * endColorQuantity + start.B * startColorQuantity)));
            }
            return colorPalette;
        }
        private Color getMeanColor(Color a, Color b)
        {
            int R = (a.R + b.R) / 2;
            int G = (a.G + b.G) / 2;
            int B = (a.B + b.B) / 2;
            return Color.FromArgb(b.A, R, G, B);
        }
        public string[] PolygonMode = {
                                          "Modulation Mode",
                                          "Decal Mode",
                                          "Toon/Highlight Shading",
                                          "Shadow Polygons"
                                      };
        /// <summary>
        /// Converts an image to grayscale
        /// </summary>
        /// <param name="inputImage">The image to be converted.</param>
        /// <returns>Return's the input image, but with grayscale</returns>
        /// <remarks></remarks>
        [Description("Converts an image to grayscale.")]
        public static Image ColorImageToGrayScaleImage(Image inputImage)
        {

            Bitmap bmp = new Bitmap(inputImage);
            System.Drawing.Imaging.BitmapData bmpData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), System.Drawing.Imaging.ImageLockMode.ReadWrite, inputImage.PixelFormat);
            int pixelBytes = Image.GetPixelFormatSize(inputImage.PixelFormat) / 8;

            IntPtr ptr = bmpData.Scan0;
            int size = bmpData.Stride * bmp.Height;
            byte[] pixels = new byte[size];
            int index = 0;
            int Y = 0;
            double mulR = 21.26 / 100;
            double mulG = 71.52 / 100;
            double mulB = 7.22 / 100;

            System.Runtime.InteropServices.Marshal.Copy(ptr, pixels, 0, size);

            for (int row = 0; row <= bmp.Height - 1; row++)
            {

                for (int col = 0; col <= bmp.Width - 1; col++)
                {
                    index = (row * bmpData.Stride) + (col * pixelBytes);

                    Y = Convert.ToInt32(Math.Round(mulR * pixels[index + 2] + mulG * pixels[index + 1] + mulB * pixels[index + 0]));
                    if ((Y > 255))
                        Y = 255;

                    pixels[index + 2] = Convert.ToByte(Y);
                    pixels[index + 1] = Convert.ToByte(Y);
                    pixels[index + 0] = Convert.ToByte(Y);

                }
            }

            System.Runtime.InteropServices.Marshal.Copy(pixels, 0, ptr, size);
            bmp.UnlockBits(bmpData);

            return bmp;

        }

        public static string[] formatNames = {
                                          "Error?", //0
                                          "A3I5 Translucent", //1
                                          "2bpp Paletted",  //2
                                          "4bpp Paletted", //3
                                          "8bpp Paletted",//4
                                          "4x4-Texeled",//5
                                          "A5I3 Translucent",//6
                                          "16-bit Color Texture" //7
                                      };
        Bitmap ConvertImage(byte[] texdata, Color[] paldata, int format, int w, int h, byte[] spdata, bool color0)
        {
            Bitmap b = new Bitmap(w, h);
            int pixelnum = b.Height * b.Width;
            try
            {
                switch (format)
                {
                    case 1:
                        for (int j = 0; j < pixelnum; j++)
                        {
                            int index = texdata[j] & 0x1f;
                            int alpha = (texdata[j] >> 5);
                            alpha = ((alpha * 4) + (alpha / 2)) * 8;
                            Color c = Color.FromArgb(alpha, paldata[index]);
                            b.SetPixel(j - ((j / (w)) * (w)), j / (w), c);
                        }
                        break;
                    case 2:
                        if (color0) paldata[0] = Color.Transparent; // made palette entry 0 transparent
                        for (int j = 0; j < pixelnum; j++)
                        {
                            uint index = texdata[j / 4];
                            index = (index >> ((j % 4) << 1)) & 3;
                            b.SetPixel(j - ((j / (w)) * (w)), j / (w), paldata[index]);
                        }
                        break;
                    case 3:
                        if (color0) paldata[0] = Color.Transparent; // made palette entry 0 transparent
                        for (int j = 0; j < pixelnum; j++)
                        {
                            uint index = texdata[j / 2];
                            index = (index >> ((j % 2) << 2)) & 0x0f;
                            b.SetPixel(j - ((j / (w)) * (w)), j / (w), paldata[index]);
                        }
                        break;
                    case 4:
                        if (color0) paldata[0] = Color.Transparent; // made palette entry 0 transparent
                        for (int j = 0; j < pixelnum; j++)
                        {
                            byte index = texdata[j];
                            b.SetPixel(j - ((j / (w)) * (w)), j / (w), paldata[index]);
                        }
                        break;
                    case 5:
                        convert_4x4texel_b(texdata, w, h, spdata, paldata, b);
                        break;
                    case 6:
                        for (int j = 0; j < pixelnum; j++)
                        {
                            int index = texdata[j] & 0x7;
                            int alpha = (texdata[j] >> 3);// & 0x1f;
                            alpha *= 8;
                            Color c = Color.FromArgb(alpha, paldata[index]);
                            b.SetPixel(j - ((j / (w)) * (w)), j / (w), c);
                        }
                        break;
                    case 7:
                        for (int j = 0; j < pixelnum; j++)
                        {
                            UInt16 p = (ushort)(texdata[j * 2] + (texdata[j * 2 + 1] << 8));
                            Color c = Color.FromArgb((((p & 0x8000) != 0) ? 0xff : 0), (((p >> 0) & 0x1f) << 3), (((p >> 5) & 0x1f) << 3), (((p >> 10) & 0x1f) << 3));
                            b.SetPixel(j - ((j / (w)) * (w)), j / (w), c);
                        }
                        break;
                }
            }
            catch
            {
                goto end2;
            }
        end2:
            return b;
        }

        /// <summary>
        /// Convert texel.
        /// </summary>
        private bool convert_4x4texel(uint[] tex, int width, int height, UInt16[] data, Color[] pal, Bitmap rgbaOut)
        {
            int w = width / 4;
            int h = height / 4;

            // traverse 'w x h blocks' of 4x4-texel
            for (int y = 0; y < h; y++)
                for (int x = 0; x < w; x++)
                {
                    int index = y * w + x;
                    UInt32 t = tex[index];
                    UInt16 d = data[index];
                    UInt16 addr = (ushort)(d & 0x3fff);
                    UInt16 mode = (ushort)((d >> 14) & 3);

                    // traverse every texel in the 4x4 texels
                    for (int r = 0; r < 4; r++)
                        for (int c = 0; c < 4; c++)
                        {
                            int texel = (int)((t >> ((r * 4 + c) * 2)) & 3);
                            Color pixel = rgbaOut.GetPixel((x * 4 + c), (y * 4 + r));

                            switch (mode)
                            {
                                case 0:
                                    pixel = pal[(addr << 1) + texel];
                                    if (texel == 3) pixel = Color.Transparent; // make it transparent, alpha = 0
                                    break;
                                case 2:
                                    pixel = pal[(addr << 1) + texel];
                                    break;
                                case 1:
                                    switch (texel)
                                    {
                                        case 0:
                                        case 1:
                                            pixel = pal[(addr << 1) + texel];
                                            break;
                                        case 2:
                                            pixel = Color.FromArgb(0xff, (int)((pal[(addr << 1)].R + pal[(addr << 1) + 1].R) / 2L), (int)((pal[(addr << 1)].G + pal[(addr << 1) + 1].G) / 2L), (int)((pal[(addr << 1)].B + pal[(addr << 1) + 1].B) / 2L));
                                            break;
                                        case 3:
                                            pixel = Color.Transparent; // make it transparent, alpha = 0
                                            break;
                                    }
                                    break;
                                case 3:
                                    switch (texel)
                                    {
                                        case 0:
                                        case 1:
                                            pixel = pal[(addr << 1) + texel];
                                            break;
                                        case 2:
                                            pixel = Color.FromArgb(0xff, (int)((pal[(addr << 1)].R * 5L + pal[(addr << 1) + 1].R * 3L) / 8), (int)((pal[(addr << 1)].G * 5L + pal[(addr << 1) + 1].G * 3L) / 8), (int)((pal[(addr << 1)].B * 5L + pal[(addr << 1) + 1].B * 3L) / 8));
                                            break;
                                        case 3:
                                            pixel = Color.FromArgb(0xff, (int)((pal[(addr << 1)].R * 3L + pal[(addr << 1) + 1].R * 5L) / 8), (int)((pal[(addr << 1)].G * 3L + pal[(addr << 1) + 1].G * 5L) / 8), (int)((pal[(addr << 1)].B * 3L + pal[(addr << 1) + 1].B * 5L) / 8));
                                            break;
                                    }
                                    break;
                            }
                            rgbaOut.SetPixel((x * 4 + c), (y * 4 + r), pixel);
                            //rgbaOut[(y * 4 + r) * width + (x * 4 + c)] = pixel;
                        }
                }
            return true;
        }

        /// <summary>
        /// Convert texel (wrapper for type safety issues).
        /// </summary>
        private void convert_4x4texel_b(byte[] tex, int width, int height, byte[] data, Color[] pal, Bitmap rgbaOut)
        {
            var list1 = new List<uint>();
            for (int i = 0; i < (tex.Length + 1) / 4; ++i)
                list1.Add(LibNDSFormats.Utils.Read4BytesAsUInt32(tex, i * 4));

            var list2 = new List<UInt16>();
            for (int i = 0; i < (data.Length + 1) / 2; ++i)
                list2.Add(LibNDSFormats.Utils.Read2BytesAsUInt16(data, i * 2));
            var b = convert_4x4texel(list1.ToArray(), width, height, list2.ToArray(), pal, rgbaOut);
        }

        private void treeView1_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e)
        {
            panel1.Invalidate();
        }
    }
}
